home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / bash / bash_110 / mint / bash110s.zoo / bash-1.10 / unwind_prot.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-07  |  6.9 KB  |  290 lines

  1. /* I can't stand it anymore!  Please can't we just write the
  2.    whole Unix system in lisp or something? */
  3.  
  4. /* Copyright (C) 1987,1989 Free Software Foundation, Inc.
  5.  
  6. This file is part of GNU Bash, the Bourne Again SHell.
  7.  
  8. Bash is free software; you can redistribute it and/or modify it under
  9. the terms of the GNU General Public License as published by the Free
  10. Software Foundation; either version 1, or (at your option) any later
  11. version.
  12.  
  13. Bash is distributed in the hope that it will be useful, but WITHOUT ANY
  14. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16. for more details.
  17.  
  18. You should have received a copy of the GNU General Public License along
  19. with Bash; see the file COPYING.  If not, write to the Free Software
  20. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  21.  
  22. /* **************************************************************** */
  23. /*                                    */
  24. /*              Unwind Protection Scheme for Bash            */
  25. /*                                    */
  26. /* **************************************************************** */
  27. #include <signal.h>
  28. #include "config.h"
  29. #include "general.h"
  30. #include "unwind_prot.h"
  31.  
  32. /* If CLEANUP is null, then ARG contains a tag to throw back to. */
  33. typedef struct _uwp {
  34.   struct _uwp *next;
  35.   Function *cleanup;
  36.   char *arg;
  37. } UNWIND_ELT;
  38.  
  39. static void
  40.   unwind_frame_discard_internal (), unwind_frame_run_internal (),
  41.   add_unwind_protect_internal (), remove_unwind_protect_internal (),
  42.   run_unwind_protects_internal ();
  43.  
  44. static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
  45.  
  46. /* Run a function without interrupts. */
  47. void
  48. without_interrupts (function, arg1, arg2)
  49.      VFunction *function;
  50.      char *arg1, *arg2;
  51. {
  52. #if defined (_POSIX_VERSION)
  53.   sigset_t set, oset;
  54.  
  55.   sigemptyset (&set);
  56.   sigaddset (&set, SIGINT);
  57.   sigprocmask (SIG_BLOCK, &set, &oset);
  58. #else
  59. #  if defined (USG)
  60.   SigHandler *old_int;
  61.  
  62.   old_int = (SigHandler *)signal (SIGINT, SIG_IGN);
  63. #  else
  64.   int oldmask = sigblock (SIGINT);
  65. #  endif
  66. #endif
  67.  
  68.   (*function)(arg1, arg2);
  69.  
  70. #if defined (_POSIX_VERSION)
  71.   sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
  72. #else
  73. #  if defined (USG)
  74.   signal (SIGINT, old_int);
  75. #  else
  76.   sigsetmask (oldmask);
  77. #  endif
  78. #endif
  79. }
  80.  
  81. /* Start the beginning of a region. */
  82. void
  83. begin_unwind_frame (tag)
  84.      char *tag;
  85. {
  86.   add_unwind_protect ((Function *)NULL, tag);
  87. }
  88.  
  89. /* Discard the unwind protects back to TAG. */
  90. void
  91. discard_unwind_frame (tag)
  92.      char *tag;
  93. {
  94.   without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
  95. }
  96.  
  97. /* Run the unwind protects back to TAG. */
  98. void
  99. run_unwind_frame (tag)
  100.      char *tag;
  101. {
  102.   without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
  103. }
  104.  
  105. /* Add the function CLEANUP with ARG to the list of unwindable things. */
  106. void
  107. add_unwind_protect (cleanup, arg)
  108.      Function *cleanup;
  109.      char *arg;
  110. {
  111.   without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
  112. }
  113.  
  114. /* Remove the top unwind protect from the list. */
  115. void
  116. remove_unwind_protect ()
  117. {
  118.   without_interrupts
  119.     (remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
  120. }
  121.  
  122. /* Run the list of cleanup functions in unwind_protect_list. */
  123. void
  124. run_unwind_protects ()
  125. {
  126.   without_interrupts
  127.     (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
  128. }
  129.  
  130. /* **************************************************************** */
  131. /*                                    */
  132. /*                        The Actual Functions                         */
  133. /*                                    */
  134. /* **************************************************************** */
  135.  
  136. static void
  137. add_unwind_protect_internal (cleanup, arg)
  138.      Function *cleanup;
  139.      char *arg;
  140. {
  141.   UNWIND_ELT *elt;
  142.  
  143.   elt = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT));
  144.   elt->cleanup = cleanup;
  145.   elt->arg = arg;
  146.   elt->next = unwind_protect_list;
  147.   unwind_protect_list = elt;
  148. }
  149.  
  150. static void
  151. remove_unwind_protect_internal ()
  152. {
  153.   UNWIND_ELT *elt = unwind_protect_list;
  154.  
  155.   if (elt)
  156.     {
  157.       unwind_protect_list = unwind_protect_list->next;
  158.       free (elt);
  159.     }
  160. }
  161.  
  162. static void
  163. run_unwind_protects_internal ()
  164. {
  165.   UNWIND_ELT *t, *elt = unwind_protect_list;
  166.  
  167.   while (elt)
  168.    {
  169.       /* This function can be run at strange times, like when unwinding
  170.     the entire world of unwind protects.  Thus, we may come across
  171.      an element which is simply a label for a catch frame.  Don't call
  172.      the non-existant function. */
  173.       if (elt->cleanup)
  174.     (*(elt->cleanup)) (elt->arg);
  175.  
  176.       t = elt;
  177.       elt = elt->next;
  178.       free (t);
  179.     }
  180.   unwind_protect_list = elt;
  181. }
  182.  
  183. static void
  184. unwind_frame_discard_internal (tag)
  185.      char *tag;
  186. {
  187.   UNWIND_ELT *elt;
  188.  
  189.   while (elt = unwind_protect_list)
  190.     {
  191.       unwind_protect_list = unwind_protect_list->next;
  192.       if (!elt->cleanup && (STREQ (elt->arg, tag)))
  193.     {
  194.       free (elt);
  195.       break;
  196.     }
  197.       else
  198.     free (elt);
  199.     }
  200. }
  201.  
  202. static void
  203. unwind_frame_run_internal (tag)
  204.      char *tag;
  205. {
  206.   UNWIND_ELT *elt;
  207.  
  208.   while (elt = unwind_protect_list)
  209.     {
  210.       unwind_protect_list = elt->next;
  211.  
  212.       /* If tag, then compare. */
  213.       if (!elt->cleanup)
  214.     {
  215.       if (strcmp (elt->arg, tag) == 0)
  216.         {
  217.           free (elt);
  218.           break;
  219.         }
  220.       free (elt);
  221.       continue;
  222.     }
  223.       else
  224.     {
  225.       (*(elt->cleanup)) (elt->arg);
  226.       free (elt);
  227.     }
  228.     }
  229. }
  230.  
  231. /* Structure describing a saved variable and the value to restore it to. */
  232. typedef struct {
  233.   int *variable;
  234.   char *desired_setting;
  235.   int size;
  236. } SAVED_VAR;
  237.  
  238. /* Restore the value of a variable, based on the contents of SV.  If
  239.    sv->size is greater than sizeof (char *), sv->desired_setting points to
  240.    a block of memory SIZE bytes long holding the value, rather than the
  241.    value itself.  This block of memory is copied back into the variable. */
  242. static void
  243. restore_variable (sv)
  244.      SAVED_VAR *sv;
  245. {
  246.  
  247.   /* I wrote this switch statement not realizing how silly some compilers
  248.      can be.  Since we expect both cases to be the same size, it really
  249.      makes no difference (today), but it irks me that I cannot express the
  250.      thought clearly. */
  251.   switch (sv->size)
  252.     {
  253.     /* case sizeof (char *): */
  254.     case sizeof (int):
  255.       *(sv->variable) = (int)sv->desired_setting;
  256.       break;
  257.  
  258.     default:
  259.       bcopy (sv->desired_setting, (char *)sv->variable, sv->size);
  260.       free (sv->desired_setting);
  261.     }
  262.  
  263.   free (sv);
  264. }
  265.  
  266. /* Save the value of a variable so it will be restored when unwind-protects
  267.    are run.  VAR is a pointer to the variable.  VALUE is the value to be
  268.    saved.  SIZE is the size in bytes of VALUE.  If SIZE is bigger than what
  269.    can be saved in a char *, memory will be allocated and the value saved
  270.    into that using bcopy (). */
  271. void
  272. unwind_protect_var (var, value, size)
  273.      int *var;
  274.      char *value;
  275.      int size;
  276. {
  277.   SAVED_VAR *s = (SAVED_VAR *)xmalloc (sizeof (SAVED_VAR));
  278.  
  279.   s->variable = var;
  280.   if (size > sizeof (char *))
  281.     {
  282.       s->desired_setting = (char *)xmalloc (size);
  283.       bcopy (value, s->desired_setting, size);
  284.     }
  285.   else
  286.     s->desired_setting = value;
  287.   s->size = size;
  288.   add_unwind_protect ((Function *)restore_variable, (char *)s);
  289. }
  290.